package morenoapp.model.app;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.prefs.BackingStoreException;
import java.util.List;
import java.util.prefs.Preferences;
import morenoapp.model.MorenoModelException;
import morenoapp.model.MorenoModelWrapper;
import morenoapp.model.data.MorenoModelFace;
import morenoapp.util.MorenoUtil;
import org.mb.listeners.IListenerManager;
import org.mb.listeners.RefListenerManager;

/**
 *
 * @author dmitry.mamonov
 */
public class MorenoApplicationData {
    private static Preferences prefs = Preferences.userNodeForPackage(MorenoApplicationData.class);

    private MorenoModelFace morenoModel = new MorenoModelWrapper();

    private IListenerManager<MorenoApplicationListener> listeners = new RefListenerManager<MorenoApplicationListener>(MorenoApplicationListener.class);

    public MorenoModelFace getMorenoModelProxy() {
        return morenoModel;
    }

    public void addApplicationListener(MorenoApplicationListener lst) {
        listeners.addListener(lst);
    }

    public void removeApplicationListener(MorenoApplicationListener lst) {
        listeners.removeListener(lst);
    }

    public void loadModel(File source) throws MorenoModelException {
        morenoModel.loadModel(source);
        addRecentOpennedResource(source.getAbsolutePath());
        listeners.getProxy().afterModelOpened(source);
    }

    public void trySaveModel() throws MorenoApplicationVetoException {
        listeners.getProxy().onSaveDoCommitChanges();
    }

    public void saveModel(File target) throws MorenoModelException {
        morenoModel.saveModel(target);
        addRecentOpennedResource(target.getAbsolutePath());
        listeners.getProxy().afterModelSaved(target);
    }

    public void addRecentOpennedResource(String resource) {
        ArrayList<ResourceDescriptor> recentResources = new ArrayList(getRecentOpennedResouces());
        ResourceDescriptor newResource = new ResourceDescriptor(resource, new Date());
        while (recentResources.remove(newResource) == true) {
            //удаление всех ресурсов из списка совпадающих с новым.
        }
        while (recentResources.size() >= 10) {
            recentResources.remove(recentResources.size() - 1);
        }
        recentResources.add(0, newResource);

        int index = 0;
        for (ResourceDescriptor rd : recentResources) {
            index++;
            String key = "recent.file." + index; //NOI18N
            String value = "" + MorenoUtil.dateToString(rd.getLastAccessTime()) + ";" + rd.getResource(); //NOI18N
            prefs.put(key, value);
        }
    }

    public List<ResourceDescriptor> getRecentOpennedResouces() {
        List<ResourceDescriptor> result = new ArrayList<ResourceDescriptor>();
        try {
            for (String key : prefs.keys()) {
                if (key.startsWith("recent.file.")) { //NOI18N
                    String value = prefs.get(key, "");
                    int index = value.indexOf(';'); //NOI18N
                    if (index >= 0) {
                        String timestampStr = value.substring(0, index);
                        Date timestampDate = MorenoUtil.stringToDate(timestampStr);
                        if (timestampDate == null) {
                            continue; //wrong data format
                        }
                        String fileName = value.substring(index + 1);
                        result.add(new ResourceDescriptor(fileName, timestampDate));
                    }
                }
            }
        } catch (BackingStoreException ex) {
            Logger.getLogger(MorenoApplicationData.class.getName()).log(Level.SEVERE, null, ex);
        }
        Collections.sort(result);
        if (result.size() > 10) {
            result = result.subList(0, 10);
        }
        return Collections.unmodifiableList(result);

    }

    /**
     * This method is declared static intentionnaly,
     * cause it is used where whole app is not initialized.
     * @return
     */
    public static String getPrefferedLocale(){
        return prefs.get("prefferedLocale",null);
    }

    /**
     * This method is declared static intentionnaly,
     * cause it is used where whole app is not initialized.
     * @return
     */
    public static void setPrefferedLocale(String name){
        prefs.put("prefferedLocale", name);
    }

    public String getInstallId(){
        return prefs.get("installId", ""+System.currentTimeMillis());
    }

    public void resetInstallID(){
        prefs.put("installId", null);
    }

    public String getHardwareInfo(){
        // TODO implement hardware lock
        return "Currently hardware lock is not implemented";
    }

    public String getCustomerEmail(){
        return prefs.get("email", "");
    }
    public void setCustomerEmail(String email){
        prefs.put("email", email);
    }

    /**
     * Получить директорию в которой последний раз производилась работа с файлами модели.
     * @return
     */
    public File getLastModelFile() {
        String dirName = prefs.get("lastModelFile", System.getProperty("user.home", ".")); //NOI18N
        File dirFile = new File(dirName);
        if (dirFile.isDirectory() || dirFile.isFile()) {
            return dirFile;
        } else {
            return new File("."); //NOI18N
        }
    }

    /**
     * Установить директорию в которой последний раз производилась работа с файлиами модели.
     */
    public void setLastModelFile(File file) {
        prefs.put("lastModelFile", file.getAbsolutePath()); //NOI18N
    }

    /**
     * Получить директорию в которой последний раз производилась работа с файлами модели.
     * @return
     */
    public File getLastExportedTableFile() {
        String dirName = prefs.get("lastExportedTableFile", System.getProperty("user.home", ".")); //NOI18N
        File dirFile = new File(dirName);
        if (dirFile.isDirectory() || dirFile.isFile()) {
            return dirFile;
        } else {
            return new File("."); //NOI18N
        }
    }

    /**
     * Установить директорию в которой последний раз производилась работа с файлиами модели.
     */
    public void setLastExportedTableFile(File file) {
        prefs.put("lastExportedTableFile", file.getAbsolutePath()); //NOI18N
    }

    public void setLastSavedReportDir(File report){
        prefs.put("lastReportDir", report.getAbsolutePath());
    }

    public File getLastSavedReportDir(){
        String reportDirName = prefs.get("lastReportDir", null);
        if (reportDirName==null){
            return null;
        } else {
            File reportDir = new File(reportDirName);
            if (reportDir.exists() && reportDir.isDirectory()){
                return reportDir;
            } else {
                return null;
            }
        }
    }

    /**
     * Дексриптор ресурса (файла) к которому в недавнее время
     * был осуществлён доступ.
     */
    public class ResourceDescriptor implements Comparable {
        protected String resource;

        protected Date lastAccessTime;

        public ResourceDescriptor(String resource, Date lastAccessTime) {
            this.resource = resource;
            this.lastAccessTime = lastAccessTime;
        }

        public Date getLastAccessTime() {
            return lastAccessTime;
        }

        public String getResource() {
            return resource;
        }

        @Override
        public int compareTo(Object o) {
            ResourceDescriptor other = (ResourceDescriptor) o;
            return -lastAccessTime.compareTo(other.lastAccessTime);
        }

        @Override
        public boolean equals(Object obj) {
            if (obj instanceof ResourceDescriptor == false) {
                return false;
            }
            ResourceDescriptor other = (ResourceDescriptor) obj;
            return resource.equals(other.resource);
        }

        @Override
        public int hashCode() {
            return resource.hashCode();
        }
    }
}
